package DEEPERsource.DEEPERsource.source.util;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class PPIExtensionLLLTest {
	
	private static final Log _log = LogFactory.getLog(PPIExtensionLLLTest.class);
	
	Dictionary dict;
	
	public PPIExtensionLLLTest(String dict){
		this.dict = new Dictionary(dict);
	}
	
	public List<Record> testSetReader(String file){ 
		List<Record> result = new ArrayList<Record>();
		BufferedReader reader;
		try {
			reader = new BufferedReader(new FileReader(file));
			String s;
			Record rec = null;
			Pattern p = Pattern.compile("word\\((\\d+),'(.+)',(\\d+),(\\d+)\\)");
			while((s = reader.readLine())!=null){
				String[] split = s.split("\\t+");
				if(split[0].equals("ID")){
					rec = new Record();
					rec.id = split[1];
				}else if(split[0].equals("sentence")){
					rec.sentence = split[1];
				}else if(split[0].equals("words")){
					rec.words = new Word[split.length-1];
					for(int i = 1; i<split.length; i++){
						Matcher m = p.matcher(split[i]);
						_log.debug(split[i]);
						if(m.matches()){
							rec.words[i-1] = new Word();
							rec.words[i-1].charOffset = new int[]{Integer.parseInt(m.group(3)),Integer.parseInt(m.group(4))};
							rec.words[i-1].word = m.group(2);
							rec.words[i-1].id = Integer.parseInt(m.group(1));
						}else{
							_log.error("Unexpected error");
						}						
					}
					result.add(rec);
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	public void writeXml(PrintStream writer, List<Record> records){
		writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		writer.append("<corpus source=\"LLLTest\">\n");
		int i = 0;
		for(Record rec : records){
			writer.append("  <document id=\"LLL.d"+i+"\" origId=\""+rec.id+"\">\n");
			writer.append("    <sentence id=\"LLL.d"+i+".s"+i+"\" origId=\""+rec.id+"\" text=\""+rec.sentence+"\">\n");
			Map<Word, String> map = dict.annotate(rec.words);
			int j = 0;
			for(Word w : map.keySet()){
				writer.append("      <entity id=\"LLL.d"+i+".s"+i+".e"+j+"\" origId=\""+w.id+"\" charOffset=\""+w.charOffset[0]+"-"+w.charOffset[1]+"\" type=\"unknown\" text=\""+w.word+"\" canonicalForm=\""+map.get(w)+"\"/>\n");
				j++;
			}
			writer.append("    </sentence>\n");
			writer.append("  </document>\n");
			i++;
		}
		writer.append("</corpus>");
	}
	
	/**
	 * 0 - path to LLL file
	 * 1 - path to the dictionary file
	 * 2 - output xml
	 * @param args
	 */
	public static void main(String[] args){
		PPIExtensionLLLTest test = new PPIExtensionLLLTest(args[1]);
		try {
			test.writeXml(new PrintStream(args[2]), test.testSetReader(args[0]));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	
	class Record{
		String id;
		String sentence;
		Word[] words;
	}
	
	class Word{
		int[] charOffset;
		String word;
		int id;
	}
	
	class Dictionary {
		
		//private static final Log _log = LogFactory.getLog(Dictionary.class);

		List<String> dictionary = new ArrayList<String>();
		Map<String,Set<String>> canonicalForms = new HashMap<String,Set<String>>();
		
		public Dictionary(String dictFile){
			try {
				BufferedReader reader = new BufferedReader(new FileReader(dictFile));
				String s;
				while((s = reader.readLine())!=null){
					if(s.equals(""))
						continue;
					String[] names = s.split("\\t");
					List<String> lNames = Arrays.asList(names);
					dictionary.addAll(lNames);
					canonicalForms.put(names[0], new HashSet<String>(lNames));
				}								
			} catch (IOException e) {
				_log.error("Can't read a dictionary.");
			}
		}
				
		/**
		 * general tagging procedure
		 * @param content
		 * @return
		 */
		public Map<Word, String> annotate(Word[] content){
			Map<Word, String> result = new HashMap<Word, String>();
			for(String entry : canonicalForms.keySet()){
				Set<String> terms = canonicalForms.get(entry);
				for(Word w : content){
					if(terms.contains(w.word)){
						result.put(w,entry);
					}
				}
			}
			return result;
		}
		
		/**
		 * Returns canonical form of a term
		 * @param term
		 * @return
		 */
		public String getCanonicalForm(String term){
			for(String key : canonicalForms.keySet()){
				if(canonicalForms.get(key).contains(term)){
					return key;
				}
			}
			return term;
		}
	}
}
